﻿using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NP.BPMReportPlatform.AnalysisInstance.Dtos;
using NP.BPMReportPlatform.AuthorizationProcessesManager;
using NP.BPMReportPlatform.DBHelper;
using NP.BPMReportPlatform.Entities.BPM_Business;
using NP.BPMReportPlatform.Entities.BPM_Business.FlowManage;
using NP.BPMReportPlatform.Entities.BPM_Engine;
using NP.BPMReportPlatform.Entities.BPM_Platform;
using NP.BPMReportPlatform.Entities.BPM_Process;
using NP.BPMReportPlatform.Entities.BPM_TodoCentre;
using NP.BPMReportPlatform.FlowManagement.Dto;
using NP.BPMReportPlatform.RestfulApis.Dto;
using NP.BPMReportPlatform.Utils;
using NP.Enterprise.Utils.Dto;
using NP.Enterprise.Utils.Http;
using Serilog;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;

namespace NP.BPMReportPlatform.FlowManagement
{
    /// <summary>
    /// 流程管理
    /// </summary>
    public class FlowManagementAppService : BPMReportPlatformAppService, IFlowManagementAppService
    {
        private readonly SqlSugarClient _db, _dbPlatform, _dbProcess, _dbEngine, _dbToDoCenter;
        private readonly IBPMUtilsAppService _bPMUtilsApp;
        private readonly INPRestHttpHelper _nPRestHttp;
        private readonly ILogger _logger;
        private readonly IAuthorizationProcessesAppService _processesAppService;
        private string _esbApiServiceUrl;
        private readonly string _frameOrderCancelUrl, _flowCancelUrl, _flowUrgingUrl, _thirdBusinessApiUrl;
        string[] btidArray = new string[] { "jtfybxspecial", "gg", "rszwbtcommon", "rszwbtspecial", "iuclgzbtspecial", "clgzbtspecial", "iujtfybxcommon", "clgzbtcommon", "iurszwbtspecial", "iuclgzbtcommon", "iujtfybxspecial", "iurszwbtcommon", "jtfybxcommon", "RszwbtCRF", "CRFJtfybxcommon" };

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="sqlSugarAppService"></param>
        public FlowManagementAppService(ISqlSugarAppService sqlSugarAppService, IBPMUtilsAppService bPMUtilsApp
            , INPRestHttpHelper nPRestHttp, IConfiguration configuration, ILogger logger,
            IAuthorizationProcessesAppService processesAppService)
        {
            _db = sqlSugarAppService.GetBusinessInstance();
            _dbPlatform = sqlSugarAppService.GetPlatformInstance();
            _dbProcess = sqlSugarAppService.GetProcessInstance();
            _dbEngine = sqlSugarAppService.GetEngineInstance();
            _dbToDoCenter = sqlSugarAppService.GetToDoCenterInstance();


            _bPMUtilsApp = bPMUtilsApp;
            _nPRestHttp = nPRestHttp;
            _logger = logger;
            _processesAppService = processesAppService;
            _esbApiServiceUrl = configuration["BPM:ESBAPIServiceUrl"];
            _frameOrderCancelUrl = configuration["BPM:FrameOrderCancelUrl"];
            _flowCancelUrl = configuration["BPM:FlowCancelUrl"];
            _flowUrgingUrl = configuration["BPM:FlowUrgingUrl"];
            _thirdBusinessApiUrl = configuration["BPM:ThirdBusinessApiUrl"];
        }

        #region 流程分类

        ///// <summary>
        ///// 获取流程分类
        ///// </summary>
        ///// <param name="input"></param>
        ///// <returns></returns>
        //public async Task<List<GetFlowCategoryOutput>> GetFlowCategory(GetFlowCategoryInput input)
        //{
        //    var logText = new StringBuilder();
        //    try
        //    {
        //        logText.AppendLine("进入GetFlowCategory");
        //        var pcStartUrl = ConfigManager.PCStartUrl;
        //        var mbStartUrl = ConfigManager.MBStartUrl;

        //        var fcmList = await _dbProcess.Queryable<FlowCategoryMapping, FlowCategory>((fcm, fc) =>
        //            new JoinQueryInfos(JoinType.Inner, fc.Code == fcm.CategoryCode)).Select((fcm, fc) =>
        //            new GetFlowCategoryMappingDto()
        //            {
        //                FlowCode = fcm.FlowCode,
        //                CategoryName = fc.Name,
        //                Type = fcm.Type
        //            }).Distinct().ToListAsync();

        //        logText.AppendLine("开始获取rstView");

        //        var processArray = _processesAppService.GetUserAuthorizationProcesses(input.EmployeeCode).Result.ToArray();
        //        var rstView = await _dbProcess.Queryable<Processes, BusinessTypes>((p, fcm) =>
        //             new JoinQueryInfos(JoinType.Inner, p.BusinessTypeId == fcm.BusinessTypeId
        //             && p.InUse == 1 && (fcm.ParentId != (Guid.Parse("7075fa51-2358-4230-aaa3-aad7fc1619dd"))
        //             || SqlFunc.EqualsNull(fcm.ParentId, null)))).Where((p, fcm) => SqlFunc.ContainsArray(processArray, p.BTID)).Select((p, fcm) =>
        //                     new GetFlowCategoryOutput()
        //                     {
        //                         Code = p.BTID,
        //                         Name = p.Name,
        //                         Url = p.ProcessId.ToString(),
        //                         CateString = fcm.Name,
        //                         Type = "P"
        //                     }).ToListAsync();

        //        rstView.ForEach(x =>
        //        {
        //            x.Url = string.Format(pcStartUrl, x.Url);
        //            x.Url_M = string.Format(mbStartUrl, x.Code);
        //            x.Cate = new List<string>() { x.CateString };
        //        });

        //        logText.AppendLine("完成获取rstView");

        //        //多分类时需单独读取
        //        var fcmBpmNewList = fcmList.Where(x => x.Type.Equals("bpmnew")).ToList();
        //        foreach (var item in fcmBpmNewList)
        //        {
        //            var flowItem = rstView.Where(x => x.Code.Equals(item.FlowCode)).FirstOrDefault();
        //            if (flowItem != null)
        //            {
        //                flowItem.Cate.Add(item.CategoryName);
        //            }
        //        }

        //        logText.AppendLine("开始获取GetOldBpmFlowCategory");
        //        var bpmFlow = await GetOldBpmFlowCategory(input, fcmList);
        //        bpmFlow.AddRange(rstView);

        //        bpmFlow.ForEach(x => x.Url_P = x.Url);

        //        logText.AppendLine("结束");
        //        return bpmFlow;
        //    }
        //    catch (Exception ex)
        //    {
        //        throw new Exception($"获取流程信息异常，异常原因：{ex.Message}");
        //    }
        //}


        /// <summary>
        /// 获取流程分类
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<List<GetFlowCategoryOutput>> GetFlowCategoryNew(GetFlowCategoryInput input)
        {
            var pcStartUrl = ConfigManager.PCStartUrl;
            var mbStartUrl = ConfigManager.MBStartUrl;
            var fcmList = await _dbProcess.Queryable<FlowCategoryMapping, FlowCategory>((fcm, fc) =>
                new JoinQueryInfos(JoinType.Inner, fc.Code == fcm.CategoryCode)).Select((fcm, fc) =>
                new GetFlowCategoryMappingDto()
                {
                    FlowCode = fcm.FlowCode,
                    CategoryCode = fc.Code,
                    CategoryName = fc.Name,
                    Type = fcm.Type
                }).ToListAsync();

            var processArray = _processesAppService.GetUserAuthorizationProcesses(input.EmployeeCode).Result.ToArray();
            var rstView = await _dbProcess.Queryable<Processes, BusinessTypes, ProcessAttribute>((p, fcm, pa) =>
                 new JoinQueryInfos(JoinType.Inner, p.BusinessTypeId == fcm.BusinessTypeId
                 && p.InUse == 1 && (fcm.ParentId != (Guid.Parse("7075fa51-2358-4230-aaa3-aad7fc1619dd"))
                 || SqlFunc.EqualsNull(fcm.ParentId, null)),
                 JoinType.Left, p.ProcessId == pa.ProcessId)).Where((p, fcm, pa) => SqlFunc.ContainsArray(processArray, p.BTID)).Select((p, fcm, pa) =>
                          new GetFlowCategoryOutput()
                          {
                              Code = p.BTID,
                              Name = p.Name,
                              Url = p.ProcessId.ToString(),
                              CateString = fcm.Code,
                              Client = string.IsNullOrEmpty(pa.Client) ? "P" : pa.Client,
                              Type = "P"
                          }).Distinct().ToListAsync();

            rstView.ForEach(x =>
            {
                x.Url = string.Format(pcStartUrl, x.Url);
                x.Url_M = string.Format(mbStartUrl, x.Code);
                x.Cate = new List<string>() { x.CateString };
            });

            //多分类时需单独读取
            var fcmBpmNewList = fcmList.Where(x => x.Type.Equals("bpmnew")).ToList();
            foreach (var item in fcmBpmNewList)
            {
                var flowItem = rstView.Where(x => x.Code.Equals(item.FlowCode)).FirstOrDefault();
                if (flowItem != null)
                {
                    flowItem.Cate.Add(item.CategoryCode);
                }
            }

            try
            {
                var bpmFlow = await GetOldBpmFlowCategory(input, fcmList, true);
                bpmFlow.AddRange(rstView);

                bpmFlow.ForEach(x =>
                {
                    x.Url_P = x.Url;
                    //if (x.Client.IsIn(new string[] { "M", "A" }))
                    //{
                    //    x.Url_M = x.Url;
                    //}
                });

                return bpmFlow;
            }
            catch (Exception ex)
            {
                _logger.Error($"GetFlowCategoryNew Error,InputParams:{JsonConvert.SerializeObject(input)},Error Response:{ex.Message}");
                rstView.ForEach(x =>
                {
                    x.Url_P = x.Url;
                });
                return rstView;
            }
        }

        /// <summary>
        /// 根据用户域账户获取有权限的流程
        /// </summary>
        /// <param name="adUser"></param>
        /// <returns></returns>
        private async Task<List<GetUserRightOutput>> GetUserRoleRight(string adUser)
        {
            var request = new
            {
                Root = new ESBWebServiceRootDto(),
                GetUserRight = new { userid = adUser }
            };
            var requestBody = JsonConvert.SerializeObject(request);

            var headers = new Dictionary<string, string>
            {
                { "sourceSystem", "BPMNEW" },
                { "serviceName", "S_XXX_BPM_GetUserRoleRight_S" }
            };

            var rstJson = await _nPRestHttp.ESBPostAsync(_esbApiServiceUrl, requestBody, headers);

            var rstArray = JsonConvert.DeserializeObject<JObject>(rstJson);
            rstJson = rstArray["GetUserRightResponse"]["GetUserRightResult"].Value<string>();
            if (string.IsNullOrWhiteSpace(rstJson))
            {
                return new List<GetUserRightOutput>();
            }
            var list = JsonConvert.DeserializeObject<List<GetUserRightOutput>>(rstJson);
            return list;
        }

        /// <summary>
        /// 获取老BPM流程分类
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private async Task<List<GetFlowCategoryOutput>> GetOldBpmFlowCategory(GetFlowCategoryInput input, List<GetFlowCategoryMappingDto> fcmList, bool isCateCode = false)
        {
            var fcmBpmList = fcmList.Where(x => x.Type.Equals("bpm")).ToList();
            var userRoleList = await GetUserRoleRight(input.ADUser);
            if (userRoleList.IsNullOrEmpty())
            {
                return new List<GetFlowCategoryOutput>();
            }
            var pcStartUrl = ConfigManager.PCMTStartUrl;

            var rstView = await _dbProcess.Queryable<BPMFlowManagement, FlowCategoryMapping>((p, fcm) =>
                 new JoinQueryInfos(JoinType.Inner, p.Code == fcm.FlowCode)).Where(p => p.IsEnable == true).Select((p, fcm) =>
                        new GetFlowCategoryOutput()
                        {
                            Code = p.Code,
                            Name = p.Name,
                            Client = p.Client,
                            Type = "P"
                        }).Distinct().ToListAsync();

            rstView = rstView.Where(x => userRoleList.Any(y => y.Code.Equals(x.Code))).ToList();
            rstView.ForEach(x =>
            {
                x.Url = string.Format(pcStartUrl, x.Code, input.ADUser);
                if (isCateCode)
                {
                    x.Cate = fcmBpmList.Where(z => z.FlowCode == x.Code).Select(z => z.CategoryCode).ToList();
                }
                else
                {
                    x.Cate = fcmBpmList.Where(z => z.FlowCode == x.Code).Select(z => z.CategoryName).ToList();
                }
            });

            return rstView;
        }

        #endregion

        ///// <summary>
        ///// 获取流程数据
        ///// </summary>
        ///// <param name="input"></param>
        ///// <returns></returns>
        //private ISugarQueryable<GetFlowOutput> GetFlowQueryable(GetFlowInput input)
        //{
        //    var listQueryable = _dbEngine.Queryable<Instances, InstanceStates, Activities, BpmTask>((i, ins, a, t) => new JoinQueryInfos(JoinType.Inner, i.InstanceId == ins.InstanceId,
        //        JoinType.Left, i.InstanceId == a.InstanceId && a.Status == 1,
        //        JoinType.Left, a.ActivityId == t.ActivityId))
        //        .WhereIF(!string.IsNullOrWhiteSpace(input.InstanceNumber), i => i.Number.Contains(input.InstanceNumber))
        //        .WhereIF(!string.IsNullOrWhiteSpace(input.AddUserName), i => i.StartUserName.Equals(input.AddUserName))
        //        .WhereIF(!input.BTID.IsNullOrEmpty(), i => SqlFunc.ContainsArray<string>(input.BTID, i.BTID))
        //        .WhereIF(input.StartCreationTime != null && input.EndCreationTime != null, (i, ins) => ins.StartTime >= input.StartCreationTime && ins.StartTime <= input.EndCreationTime)
        //        .WhereIF(!string.IsNullOrWhiteSpace(input.Topic), i => i.Topic.Contains(input.Topic)).Select((i, ins, a, t) =>
        //        new GetFlowOutput()
        //        {
        //            InstanceNumber = i.Number,
        //            Topic = i.Topic,
        //            StartUserName = i.StartUserName,
        //            StartTime = ins.StartTime,
        //            LatestActivityName = ins.LatestActivityName,
        //            Status = ins.Status,
        //            StatusName = ins.StatusName,
        //            ActivityResolverName = t.ActivityResolverName
        //        }).MergeTable().Distinct().OrderBy(ins => ins.StartTime, OrderByType.Desc);
        //    return listQueryable;
        //}


        /// <summary>
        /// 导出流程数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private async Task<List<GetFlowOutput>> ExportFlowData(GetFlowInput input)
        {
            var defaultDate = DateTime.Now.AddDays(-60);

            var list = await _db.Queryable<BusinessProcessesNew>().WhereIF(!string.IsNullOrWhiteSpace(input.InstanceNumber), b => b.InstanceId.Contains(input.InstanceNumber))
                .WhereIF(!string.IsNullOrWhiteSpace(input.AddUserName), b => b.StartUserName.Equals(input.AddUserName))
                .WhereIF(!input.BTID.IsNullOrEmpty(), b => SqlFunc.ContainsArray(input.BTID, b.BTID))
                .WhereIF(input.StartCreationTime == null, b => b.StartTime >= defaultDate)
                .WhereIF(input.StartCreationTime != null && input.EndCreationTime != null, b => b.StartTime >= input.StartCreationTime && b.StartTime <= input.EndCreationTime)
                .WhereIF(!string.IsNullOrWhiteSpace(input.Topic), b => b.ProcessTopic.Contains(input.Topic)).Select(b =>
                new GetFlowOutput()
                {
                    InstanceNumber = b.InstanceId,
                    Topic = b.ProcessTopic,
                    StartUserName = b.StartUserName,
                    StartTime = b.StartTime,
                    //LatestActivityName = t.ActivityName,
                    StatusName = b.ProcessStatusName,
                    //ActivityResolverName = t.UserName
                }).MergeTable().Distinct().OrderBy(ins => ins.StartTime, OrderByType.Desc).ToListAsync();
            return list;
        }

        /// <summary>
        /// 查询数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<GetFlowOutput>> GetAllAsync(GetFlowInput input)
        {
            RefAsync<int> totalCount = 0;

            var defaultDate = DateTime.Now.AddDays(-60);

            var listViewDto = await _dbEngine.Queryable<Instances, InstanceStates>(
                (i, ins) => new JoinQueryInfos(JoinType.Inner, i.InstanceId == ins.InstanceId))
                .WhereIF(!string.IsNullOrWhiteSpace(input.InstanceNumber), i => i.Number.Contains(input.InstanceNumber))
                .WhereIF(!string.IsNullOrWhiteSpace(input.AddUserName), i => i.StartUserName.Equals(input.AddUserName))
                .WhereIF(!input.BTID.IsNullOrEmpty(), i => SqlFunc.ContainsArray<string>(input.BTID, i.BTID))
                .WhereIF(input.StartCreationTime == null && string.IsNullOrWhiteSpace(input.InstanceNumber) &&
                    string.IsNullOrWhiteSpace(input.Topic), (i, ins) => ins.StartTime >= defaultDate)
                .WhereIF(input.StartCreationTime != null && input.EndCreationTime != null,
                    (i, ins) => ins.StartTime >= input.StartCreationTime && ins.StartTime <= input.EndCreationTime)
                .WhereIF(!string.IsNullOrWhiteSpace(input.Topic), i => i.Topic.Contains(input.Topic))
                .WhereIF(!input.HRBPPermissionIsAdmin && input.IsHRBPPermission, i => input.HRBPPermissionUserIds.Contains(i.StartUserId))
                .Select((i, ins) => new GetFlowOutput()
                {
                    InstanceId = i.InstanceId,
                    InstanceNumber = i.Number,
                    Topic = i.Topic,
                    StartUserName = i.StartUserName,
                    StartTime = ins.StartTime,
                    LatestActivityName = ins.LatestActivityName,
                    Status = ins.Status,
                    StatusName = ins.StatusName,
                }).MergeTable().Distinct().OrderBy(ins => ins.StartTime, OrderByType.Desc)
                .ToPageListAsync(input.PageIndex, input.PageSize, totalCount);

            var instanceIds = listViewDto.Select(x => x.InstanceId);

            var activityDatas = await _dbEngine.Queryable<Activities, Tasks>((a, b) =>
                new JoinQueryInfos(JoinType.Left, a.ActivityId.ToString() == b.ActivityId))
                .Where(a => instanceIds.Contains(a.InstanceId) && a.Status == 1)
                .Select((a, b) => new ActivitieTaskModel
                {
                    InstanceId = a.InstanceId,
                    InstanceNumber = a.InstanceNumber,
                    Name = a.Name,
                    ArriveTime = a.ArriveTime,
                    ElapsedTime = a.ElapsedTime,
                    FinishTime = a.FinishTime,
                    UserId = b.UserId,
                    UserName = b.UserName,
                    GrandNodeId = a.GrandNodeId,
                }).ToListAsync();

            var userId = await _dbPlatform.Queryable<Users>()
                .Where(x => x.WorkNumber.Equals(CurrentUser.UserName))
                .Select(x => x.UserId).FirstAsync();

            var userIds = activityDatas.Select(x => x.UserId);
            var users = await _dbPlatform.Queryable<Users>()
                .Where(x => userIds.Contains(x.UserId.ToString()))
                .Select(x => new { x.WorkNumber, x.UserId }).ToListAsync();

            listViewDto.ForEach(x =>
            {
                x.Url = _bPMUtilsApp.GetProcessUrl(x.InstanceNumber, userId.ToString());
                var activityData = activityDatas.Where(q => x.InstanceId.Equals(q.InstanceId));
                var userStrs = new List<string>();
                foreach (var data in activityData)
                {
                    var user = users.FirstOrDefault(q => q.UserId.ToString() == data.UserId);
                    if (user == null)
                    {
                        continue;
                    }
                    userStrs.Add($"{data.UserName}({user.WorkNumber})");
                }
                x.ActivityResolverName = string.Join(";", userStrs);
            });

            //返回结果
            return new PagedResultDto<GetFlowOutput>()
            {
                TotalCount = totalCount,
                Items = listViewDto
            };
        }


        /// <summary>
        /// 导出数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<List<GetFlowOutput>> ExportAllAsync(GetFlowInput input)
        {
            return await ExportFlowData(input);
        }

        /// <summary>
        /// 查询框架订单数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<GetFlowOutput>> GetKJDDAllAsync(GetFlowInput input, List<string> workNumbers)
        {
            input.BTID = btidArray;
            if (workNumbers.Any())
            {
                var userIds = await _dbPlatform.Queryable<Users>()
                    .Where(x => workNumbers.Contains(x.WorkNumber) && x.Status == 1)
                    .Select(x => x.UserId).ToListAsync();
                input.HRBPPermissionUserIds = userIds;
            }
            input.IsHRBPPermission = true;
            var list = await GetAllAsync(input);
            return list;
        }

        /// <summary>
        /// 导出框架订单数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<List<GetFlowOutput>> ExportKJDDAllAsync(GetFlowInput input)
        {
            input.BTID = btidArray;
            return await ExportFlowData(input);
        }

        /// <summary>
        /// 框架订单作废
        /// </summary>
        /// <param name=""></param>
        /// <returns></returns>
        public async Task FrameOrderCancelAsync(FrameOrderCancelInput input)
        {
            input.OperatingUser = CurrentUser.UserName;
            var rst = await _nPRestHttp.PostAsync<ApiResultDto>(_frameOrderCancelUrl, input);
            if (rst.Code == 200)
            {
                var array = JsonConvert.DeserializeObject<JObject>(rst.Result.ToString());
                var returnValue = Convert.ToBoolean(array.Value<string>("ReturnValue"));
                if (!returnValue)
                {
                    throw new Exception($"作废失败！原因：{array.Value<string>("Message")}");
                }
            }
            else
            {
                throw new Exception("接口调用异常！");
            }
        }

        /// <summary>
        /// 车辆交通费报表作废需传true
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task FrameOrderCancelNoSAPAsync(FrameOrderCancelInput input)
        {
            input.NoSap = true;
            await FrameOrderCancelAsync(input);
        }

        /// <summary>
        /// 流程作废
        /// </summary>
        /// <param name="instanceNumber"></param>
        /// <returns></returns>
        public async Task FlowCancelAsync(FlowCancelInput input)
        {
            var rst = await _nPRestHttp.PutAsync<string>(string.Format(_flowCancelUrl, input.InstanceNumber), null);

            try
            {
                var businessesInfo = await _db.Queryable<BusinessProcessesNew>().FirstAsync(x => x.InstanceId == input.InstanceNumber && x.ProcessStatusCode == "approved");
                if (businessesInfo != null)
                {
                    businessesInfo.ProcessStatusCode = "canceled";
                    businessesInfo.ProcessStatusName = "已终止";
                    await _db.Updateable(businessesInfo).ExecuteCommandAsync();
                }

                // 记录日志
                var history = new InstanceOperateHistory
                {
                    Id = Guid.NewGuid(),
                    InstanceNumber = input.InstanceNumber,
                    CreateTime = DateTime.Now,
                    Creator = CurrentUser.UserName,
                    InstanceCategory = 0,
                    OpearteType = 1,
                    Result = rst,
                    InputParam = JsonConvert.SerializeObject(input),
                };

                _logger.Information(JsonConvert.SerializeObject(history));

                await _db.Insertable(history).ExecuteCommandAsync();
            }
            catch (Exception ex)
            {
                _logger.Error($"{JsonConvert.SerializeObject(input)}：{ex.Message}");
            }
        }

        /// <summary>
        /// 流程催办
        /// </summary>
        /// <param name="instanceNumber"></param>
        /// <returns></returns>
        public async Task FlowUrgingAsync(FlowUrgingInput input)
        {
            try
            {
                var rst = await _nPRestHttp.PutAsync<string>(string.Format(_flowUrgingUrl, input.InstanceNumber), null);
            }
            catch (Exception)
            {
                //记录报错的日志
                var urgingErrorLogs = new UrgingErrorLogs()
                {
                    UrgingErrorLogId = Guid.NewGuid(),
                    Remark = JsonConvert.SerializeObject(input),
                    CreateTime = DateTime.Now,
                };
                await _db.Insertable(urgingErrorLogs).ExecuteCommandAsync();
            }
        }

        /// <summary>
        /// 获取新BPM待办
        /// </summary>
        /// <returns></returns>
        public async Task<List<GetBPMNEWToDoOutput>> GetBPMNEWToDoAsync()
        {
            var dbToDoList = await _dbToDoCenter.Queryable<ToDoCenterTask>().
                Where(x => x.Type == 1 && x.Status == 1).
                Select(x => new
                {
                    x.UserId,
                    x.BusinessNumber
                }).ToListAsync();

            var userIdArray = dbToDoList.Select(x => x.UserId).Distinct().ToArray();
            var dbUserList = await _dbPlatform.Queryable<Users>().
                Where(x => x.Status == 1 && userIdArray.Contains(x.UserId)).
                Select(x => new
                {
                    x.UserId,
                    x.WorkNumber
                }).Distinct().ToListAsync();

            var query = from a in dbToDoList
                        join b in dbUserList on a.UserId equals b.UserId
                        select new GetBPMNEWToDoOutput()
                        {
                            OrderNumber = a.BusinessNumber,
                            EmployeeCode = b.WorkNumber
                        };
            var rst = query.ToList();
            return rst;
        }

        /// <summary>
        /// 获取BPM已办
        /// </summary>
        /// <returns></returns>
        public async Task<List<GetBPMDoneOutput>> GetBPMDoneAsync(GetBPMDoneInput input)
        {
            var startDate = input.LatestArriveTime;
            var endDate = input.LatestArriveTime.AddDays(1);
            return await _dbEngine.Queryable<Instances>().InnerJoin<InstanceStates>((a, b) => a.InstanceId == b.InstanceId).
                Where((a, b) => b.Status == 2 && b.LatestArriveTime >= startDate && b.LatestArriveTime < endDate).
                Select((a, b) => new GetBPMDoneOutput()
                {
                    InstallNumber = a.Number,
                    StartDate = b.StartTime
                }).ToListAsync();
        }



        ///// <summary>
        ///// 获取用户待办详情
        ///// </summary>
        ///// <returns></returns>
        //public async Task GetUserTodoDetailAsync(Guid taskId,Guid userId)
        //{
        //    var taskList = _dbEngine.Queryable<BpmTask>()
        //        .Where(t => t.TaskId == taskId)
        //        .Select(t => new { t.UserId, t.Status });

        //    if (taskList.Count() > 0)
        //    {
        //        var isExist = taskList.Where(t => t.UserId.Equals(userId) && t.Status == ((int)TaskCommonStatus.Processing)).Any();
        //        if(isExist)
        //        {

        //        }
        //    }
        //}


        /// <summary>
        /// 依据FlowCancelTask表数据 批量作废流程
        /// </summary>
        /// <returns></returns>
        public async Task FlowBatchCancelAsync(FlowBatchCancelInput input)
        {
            if (string.IsNullOrWhiteSpace(input.BatchNumber))
            {
                throw new Exception("请填写批次号");
            }
            if (string.IsNullOrEmpty(input.OperatingUser))
            {
                throw new Exception("请填写用户工号或账号");
            }
            if (string.IsNullOrEmpty(input.Comment))
            {
                throw new Exception("请填写说明");
            }

            var user = await _dbPlatform.Queryable<Users>().With(SqlWith.NoLock)
                .Where(t => (t.UserLoginId.ToLower() == input.OperatingUser.ToLower() ||
                t.WorkNumber.ToLower() == input.OperatingUser.ToLower()) && t.Status == 1).FirstAsync();
            if (user == null)
            {
                throw new ArgumentNullException("操作人账户不存在！");
            }

            var dataList = _db.Queryable<FlowCancelTask>().Where(x =>
                x.BatchNumber == input.BatchNumber && !string.IsNullOrWhiteSpace(x.InstanceNumber) &&
                (x.OperateType == 1 || x.OperateType == 2) && x.IsOperated == 0).ToList();
            foreach (var data in dataList)
            {
                if (data.OperateType == 1)
                {
                    var rst = await _nPRestHttp.PutAsync<string>(string.Format(_flowCancelUrl, data.InstanceNumber), null);
                    data.IsOperated = 1;
                    data.OperateTime = DateTime.Now;
                    if (!string.IsNullOrEmpty(rst))
                    {
                        var res = JsonConvert.DeserializeObject<FlowCancelOutput>(rst);
                        data.Code = res?.Code;
                        data.Message = res?.Message;
                    }
                    await _db.Updateable(data).ExecuteCommandAsync();
                }
                else if (data.OperateType == 2)
                {
                    var req = new
                    {
                        instanceNumber = data.InstanceNumber,
                        comment = input.Comment,
                        operatingTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                        operatingUser = input.OperatingUser
                    };
                    var rst = await _nPRestHttp.PostAsync<FlowCancelOutput>($"{_thirdBusinessApiUrl}ThirdFlow/Cancel",
                        JsonConvert.SerializeObject(req));
                    data.IsOperated = 1;
                    data.OperateTime = DateTime.Now;
                    if (rst != null)
                    {
                        data.Code = rst?.Code;
                        data.Message = rst?.Message;
                    }
                    await _db.Updateable(data).ExecuteCommandAsync();
                }
                await Task.Delay(1000);
            }
        }

        /// <summary>
        /// 获取流程实例状态
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<List<GetProcessInstanceStatusOutput>> GetProcessInstanceStatus(List<GetProcessInstanceStatusInput> input)
        {
            var instanceNumberArray = input.Select(x => x.InstanceNumber).ToList();
            var listViewDto = await _dbEngine.Queryable<Instances, InstanceStates>((a, b) =>
                new JoinQueryInfos(JoinType.Inner, a.InstanceId == b.InstanceId))
                .Where(a => instanceNumberArray.Contains(a.Number))
                .Select((a, b) => new GetProcessInstanceStatusOutput
                {
                    InstanceId = a.InstanceId,
                    InstanceNumber = a.Number,
                    Status = b.Status,
                    StatusName = b.StatusName,
                    CurrentApprovalSteps = b.LatestActivityName,
                    CurrentApproverUserName = ""
                }).ToListAsync();

            var activityDatas = await _dbEngine.Queryable<Tasks>().Where(a => instanceNumberArray.Contains(a.InstanceNumber) && a.Status == 1)
                    .Select(a => new { a.InstanceId, a.UserId, a.UserName }).ToListAsync();

            var userIds = activityDatas.Select(x => x.UserId);
            var users = await _dbPlatform.Queryable<Users>()
                .Where(x => userIds.Contains(x.UserId.ToString()))
                .Select(x => new { x.WorkNumber, x.UserId }).ToListAsync();

            listViewDto.ForEach(x =>
            {
                var activityData = activityDatas.Where(q => x.InstanceId.Equals(q.InstanceId));
                var userStrs = new List<string>();
                foreach (var data in activityData)
                {
                    var user = users.FirstOrDefault(q => q.UserId.ToString() == data.UserId);
                    if (user == null)
                    {
                        continue;
                    }
                    userStrs.Add($"{data.UserName}({user.WorkNumber})");
                }
                x.CurrentApproverUserName = string.Join(";", userStrs);
            });

            return listViewDto;
        }
    }
}
